#version 330 core
out vec4 FragColor;

in VS_OUT {
    vec3 FragPos;
    vec2 TexCoords;
    vec3 TangentLightPos;
    vec3 TangentViewPos;
    vec3 TangentFragPos;
} fs_in;

struct PointLight 
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;

    float constant;
    float linear;
    float quadratic;
};

struct Material 
{
    sampler2D diffuse;
    sampler2D normal;
    sampler2D parallaxMap;
    float shininess;
};

uniform Material material;
uniform PointLight pointLight;
uniform float height_scale;

vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir, vec2 texCoords);
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir);

void main()
{          
    vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.FragPos);
    vec2 texCoords = ParallaxMapping(fs_in.TexCoords,  viewDir);
    //texCoords = fs_in.TexCoords;

    if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)
        discard;

    vec3 normal = texture(material.normal, texCoords).rgb;
    normal = normalize(normal * 2.0 - 1.0);
               
    vec3 lighting = CalcPointLight(pointLight, normal, fs_in.FragPos, viewDir, texCoords);
    FragColor = vec4(lighting, 1.0);
}

vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir, vec2 texCoords)
{
    vec3 lightDir = normalize(fs_in.TangentLightPos - fragPos);
    float distance    = length(fs_in.TangentLightPos - fragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    

    vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, texCoords));

    float diff = max(dot(normal, lightDir), 0.0);
    vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, texCoords));

    vec3 halfwayDir = normalize(lightDir + viewDir);  
    float spec = pow(max(dot(normal, halfwayDir), 0.0), material.shininess);
    vec3 specular = spec * light.specular;  

    return (ambient + diffuse + specular) * attenuation;
}

vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{ 
    // 深度层数
    const float minLayers = 8.0;
    const float maxLayers = 32.0;
    float numLayers = mix(maxLayers, minLayers, max(dot(vec3(0.0, 0.0, 1.0), viewDir), 0.0));
    // 计算每层的大小
    float layerDepth = 1.0 / numLayers;
    // 当前层的深度
    float currentLayerDepth = 0.0;
    // 每层沿P向量方向的纹理坐标偏移量
    vec2 P = viewDir.xy * height_scale; 
    vec2 deltaTexCoords = P / numLayers;

    // 获取初始值
    vec2  currentTexCoords     = texCoords;
    float currentParallaxMapValue = texture(material.parallaxMap, currentTexCoords).r;
  
    while(currentLayerDepth < currentParallaxMapValue)
    {
        // 沿P方向偏移纹理坐标
        currentTexCoords -= deltaTexCoords;
        // 获取当前纹理坐标处的深度图值
        currentParallaxMapValue = texture(material.parallaxMap, currentTexCoords).r;
        // 获取下一层的深度
        currentLayerDepth += layerDepth;
    }

    // 获取碰撞前的纹理坐标（逆向操作）
    vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

    // 获取碰撞前后深度值以进行线性插值
    float afterDepth  = currentLayerDepth - currentParallaxMapValue;//修改处
    float beforeDepth = texture(material.parallaxMap, prevTexCoords).r - currentLayerDepth + layerDepth;
 
    // 纹理坐标的插值
    float weight = afterDepth / (afterDepth + beforeDepth);//修改处
    vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

    return finalTexCoords;
}